import {FormCascader} from '../components'
import gql from 'graphql-tag'
import {compose, withState} from 'recompose'
import {componentWillMount, withData} from '../hoc'
import {lensIndex, lensProp, omit, over, set} from '../util'
import {withApollo} from 'react-apollo'


const loadData = async ({option, query, setState, options, needTown, initialValue}) => {
    const queryAllCity = ({filter}) => query({
        query: gql`query AllCities($filter:CityFilter){allCities(filter:$filter){ id name parent{id name}}}`,
        variables: {filter}
    })
    const queryCity = (id) => query({
        query: gql`query City($id:ID!){City(id:$id){ id name leaf parent{id name}}}`,
        variables: {id}
    })

    if (initialValue) {
        const data = await queryAllCity({filter: {OR: [{parentId: null}, {parentId: undefined}]}});
        const roots = data.data.allCities || [];
        options = roots.map((root, index) => ({
            value: root.id,
            label: root.name,
            isLeaf: false,
            index
        }));

        let value = [];

        const city = (await queryCity(initialValue)).data.City;
        let rootIndex = roots.findIndex(r => r.id == city.parent.id);
        const brothers = (await queryAllCity({filter: {parentId: city.parent.id}})).data.allCities || [];
        if (rootIndex > -1) {
            //no-needTown
            const rootChildren = brothers.map((b, index) => ({
                value: b.id,
                label: b.name,
                isLeaf: false,
                index
            }));
            options = set(lensIndex(rootIndex), set(lensProp('children'), rootChildren, options[rootIndex]), options);
            value = [roots[rootIndex].id, initialValue];
        } else {
            const parent = (await queryCity(city.parent.id)).data.City || {};
            const parentBrothers = (await queryAllCity({filter: {parentId: parent.parent.id}})).data.allCities || [];
            const parentIndex = parentBrothers.findIndex(p => p.id == city.parent.id);
            const rootIndex = roots.findIndex(r => r.id == parentBrothers[parentIndex].parent.id);

            let rootChildren = parentBrothers.map((b, index) => ({
                value: b.id,
                label: b.name,
                isLeaf: true,
                index
            }));

            rootChildren = set(
                lensIndex(parentIndex),
                set(
                    lensProp('children'),
                    brothers.map((b, index) => ({
                        value: b.id,
                        label: b.name,
                        isLeaf: b.leaf,
                        index
                    })),
                    parentBrothers[parentIndex]
                ),
                rootChildren
            )
            options = set(lensIndex(rootIndex), set(lensProp('children'), rootChildren, options[rootIndex]), options);
            value = [roots[rootIndex].id, parent.id, initialValue];
        }
        setState({options, value})
    } else {
        if (!needTown && option && option.length == 2) return
        const filter = option
            ? {parentId: option.length == 1 ? option[0].value : option[1].value}
            : {OR: [{parentId: null}, {parentId: undefined}]};

        const data = (await queryAllCity({filter})).data;
        if (!option) {
            const roots = data.allCities || [];
            let options = roots.map((root, index) => ({
                value: root.id,
                label: root.name,
                isLeaf: false,
                index
            }));
            setState({options});
        } else if (option.length == 1) {
            const allCities = (data.allCities || []).map((city, index) => ({
                value: city.id,
                label: city.name,
                isLeaf: needTown ? false : true,
                index
            }));
            setState({
                options: set(
                    lensIndex(option[0].index),
                    set(
                        lensProp('children'),
                        allCities,
                        options[option[0].index]
                    ),
                    options
                )
            })
        } else {
            const allCities = (data.allCities || []).map((city) => ({
                value: city.id,
                label: city.name,
            }));

            let root = options[option[0].index];
            let parent = (root.children || [])[option[1].index];

            setState({
                options: set(
                    lensIndex(option[0].index),
                    set(
                        lensProp('children'),
                        set(
                            lensIndex(option[1].index),
                            set(lensProp('children'), allCities, parent),
                            root.children || []
                        ),
                        root
                    ),
                    options
                )
            })
        }
    }
}


const AddressSelect = props => {
    const {setState, needTown, state: {options, value}, client: {query}} = props;


    return (
        <FormCascader {...omit(['initialValue'], props)}
                      options={options}
                      initialValue={value}
                      loadData={option => loadData({option, query, setState, options, needTown})}
        />
    )
}


export default compose(
    withData,
    withApollo,
    withState('state', 'setState', {
        options: [],
        value: []
    }),
    componentWillMount([
        ({setState, initialValue, needTown, client: {query}}) => loadData({
            needTown,
            initialValue,
            option: null,
            query,
            setState
        })
    ])
)(AddressSelect)